
package ploy.lang;

import java.io.*;
import java.util.*;
import java.text.*;

import org.objectweb.asm.*;
import org.objectweb.asm.util.*;
import org.objectweb.asm.commons.*;

import ploy.compiler.*;
import ploy.library.*;

/**
 * Repl is the read-eval-print-loop for Ploy.  It 1. reads input off stdin,
 * 2. evaluates this input, 3. prints the result, 4. loops.
 * This is a "main" class; it can be invoked from the command line.
 */
public class Repl {
    
    public static void loadStandardLibrary( SyntacticEnvironment se )
	throws RuntimeError
    {
	Globals.addGlobal( new Symbol( "cons" ), new Cons( ) );
	Globals.addGlobal( new Symbol( "car" ), new Car( ) );
	Globals.addGlobal( new Symbol( "cdr" ), new Cdr( ) );
	Globals.addGlobal( new Symbol( "load" ), new Load( se ) );
    }

    /** Given an AST, compiles and invokes it. */
    public static void invokeAST( AST a ) 
	throws ParseException, RuntimeError
    {
        Closure closure = AST.compileThunk( a, AST.ployClassLoader );
	
        DynamicObject result = closure.invoke0( );
        System.out.println( result.toString() );
    }
 
    /** The main read-eval-print loop. */
    public static void main ( String[] args ) {

	PushbackReader inPb = 
	    new PushbackReader( new InputStreamReader( System.in ) );

	System.out.println( "Ploy 0.0" );

	DynamicObject nextSexp;
	AST nextAST;
	SyntacticEnvironment se = SyntacticEnvironment.newReplEnvironment( );

	try {
	    loadStandardLibrary( se );
	} catch ( RuntimeError e ) {
	    System.out.println( "While loading system library: " +
				"[RUNTIME ERROR] " + 
				e.getMessage() );
	    return;
	}

	for ( ; ; ) {
	    
	    try {
		System.out.print( "> " );
		nextSexp = DynamicObject.readSexp( inPb );
		System.out.println( nextSexp.toString( ) );
	    } catch ( IOException e ) {
		System.out.println( "[READ ERROR] " + e.getMessage( ) );
		continue;
	    }
	    try {
		nextAST = AST.parse( nextSexp, se );
		System.out.println( nextAST.toString( ) );
		invokeAST( nextAST );
	    } catch ( ParseException p ) {
		System.out.println( "[PARSE ERROR] " + p.getMessage( ) );
		continue;
	    } catch ( RuntimeError c ) {
		System.out.println( "[RUNTIME ERROR] " + c.getMessage( ) );
		continue;
	    }
	}

    }
   
    
}